#include <sstream>
#include <crypto/secureDataMap.h>

namespace crypto {
SecureDataMap::SecureDataMap(std::shared_ptr<cipherManager> manager) : manager(std::move(manager)){}

void SecureDataMap::addItemBySecureDataItem(SecureDataMapItem &&item) {
	data.push_back(item);
	data.back().setManager(manager);
}

void SecureDataMap::addItemBySecureDataItem(const SecureDataMapItem &item) {
	data.push_back(item);
	data.back().setManager(manager);
}

void SecureDataMap::addItemByStrings(const std::string& service, const std::string& login, std::string unecryptedPassword, std::string unecryptedNotes) {
	auto pass = manager->encrypt(Botan::secure_vector<uint8_t>(unecryptedPassword.begin(), unecryptedPassword.end()), false);
	auto notes = manager->encrypt(Botan::secure_vector<uint8_t>(unecryptedNotes.begin(), unecryptedNotes.end()), false);
	data.emplace_back(service, login, pass, notes, getCipherManager());
	unecryptedPassword.resize(0);
	unecryptedNotes.resize(0);
}

void SecureDataMap::deleteItem(std::vector<SecureDataMapItem>::const_iterator iter) {
	data.erase(iter);
}

std::vector<SecureDataMapItem>::const_iterator SecureDataMap::getData(const std::string &login) const {
	auto it = std::find_if(data.begin(), data.end(), [&login](auto item){
		return item.getDecryptedData(utils::DataType::LOGIN).toStdString() == login;
	});
	if (it != data.end()) {
		return it;
	} else {
		return data.end();
	}
}

std::vector<SecureDataMapItem>::iterator SecureDataMap::getDataViaLoginAndServiceName(const std::string &login, const std::string &service) {
	auto it = std::find_if(data.begin(), data.end(), [&login, &service](auto item){
		return item.getDecryptedData(utils::DataType::LOGIN).toStdString() == login && item.getDecryptedData(utils::DataType::SERVICE_NAME).toStdString() == service;
	});
	if (it != data.end()) {
		return it;
	} else {
		return data.end();
	}
}


void SecureDataMap::clearData() {
	for (auto& item : data) {
		item.clear();
	}
}

void SecureDataMap::deleteItemByLogin(const std::string& login) {
	auto it = getData(login);
	deleteItem(it);
}

std::size_t SecureDataMap::count() const {
	return data.size();
}

std::vector<SecureDataMapItem>::const_iterator SecureDataMap::begin() const {
	return this->data.begin();
}

std::vector<SecureDataMapItem>::const_iterator SecureDataMap::end() const {
	return this->data.end();
}

std::vector<SecureDataMapItem>::iterator SecureDataMap::begin() {
	return this->data.begin();
}

std::vector<SecureDataMapItem>::iterator SecureDataMap::end() {
	return this->data.end();
}

std::shared_ptr<cipherManager> SecureDataMap::getCipherManager() const {
	return this->manager;
}

Botan::secure_vector<uint8_t> SecureDataMap::writeMapInSecureVector() {
	std::stringstream oss;
	auto newIV = manager->generateIV();
	for (auto& item : *this) {
		item.reDecryptData(newIV);
		oss << to_string(item) <<'\n';
	}
	std::string sdm_str = oss.str();
	Botan::secure_vector<uint8_t> dataToEncrypt(sdm_str.begin(), sdm_str.end());
	manager->getCipher()->setIV(newIV.bits_of());
	manager->getCipher()->saveIVInByteArray(dataToEncrypt);
	return dataToEncrypt;
}
}
